{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torchvision\n",
    "from torch.utils.data import DataLoader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<torch._C.Generator at 0x21809518970>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n_epochs = 3\n",
    "batch_size_train = 64\n",
    "batch_size_test = 1000\n",
    "learning_rate = 0.01\n",
    "momentum = 0.5\n",
    "log_interval = 100\n",
    "random_seed = 1\n",
    "torch.manual_seed(random_seed)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to D:/data/MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "733780794dc34fe8ac5e4f24b4d7aea8",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(HTML(value=''), FloatProgress(value=1.0, bar_style='info', layout=Layout(width='20px'), max=1.0…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting D:/data/MNIST\\raw\\train-images-idx3-ubyte.gz to D:/data/MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to D:/data/MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4c300f676e8d47a3b2e434a64e165af5",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(HTML(value=''), FloatProgress(value=1.0, bar_style='info', layout=Layout(width='20px'), max=1.0…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting D:/data/MNIST\\raw\\train-labels-idx1-ubyte.gz to D:/data/MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to D:/data/MNIST\\raw\\t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "f2dc79aa763547168d1ea75e81421e07",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(HTML(value=''), FloatProgress(value=1.0, bar_style='info', layout=Layout(width='20px'), max=1.0…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting D:/data/MNIST\\raw\\t10k-images-idx3-ubyte.gz to D:/data/MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to D:/data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "45ed2033e58842809d155a8f34f7a075",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(HTML(value=''), FloatProgress(value=1.0, bar_style='info', layout=Layout(width='20px'), max=1.0…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting D:/data/MNIST\\raw\\t10k-labels-idx1-ubyte.gz to D:/data/MNIST\\raw\n",
      "Processing...\n",
      "Done!\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\ProgramFiles\\anaconda3\\lib\\site-packages\\torchvision\\datasets\\mnist.py:480: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  ..\\torch\\csrc\\utils\\tensor_numpy.cpp:141.)\n",
      "  return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)\n"
     ]
    }
   ],
   "source": [
    "train_loader = torch.utils.data.DataLoader(\n",
    "    torchvision.datasets.MNIST('D:/data/', train=True, download=False,\n",
    "    transform=torchvision.transforms.Compose([\n",
    "        torchvision.transforms.ToTensor(),\n",
    "        torchvision.transforms.Normalize(\n",
    "            (0.1307,), (0.3081,))\n",
    "        ])),\n",
    "    batch_size=batch_size_train, shuffle=True)\n",
    "test_loader = torch.utils.data.DataLoader(\n",
    "    torchvision.datasets.MNIST('D:/data/', train=False, download=False,\n",
    "    transform=torchvision.transforms.Compose([\n",
    "        torchvision.transforms.ToTensor(),\n",
    "        torchvision.transforms.Normalize(\n",
    "            (0.1307,), (0.3081,))\n",
    "        ])),\n",
    "    batch_size=batch_size_test, shuffle=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.conv1 = nn.Conv2d(1, 10, kernel_size=5)\n",
    "        self.conv2 = nn.Conv2d(10, 20, kernel_size=5)\n",
    "        self.conv2_drop = nn.Dropout2d()\n",
    "        self.fc1 = nn.Linear(320, 50)\n",
    "        self.fc2 = nn.Linear(50, 10)\n",
    "    def forward(self, x):\n",
    "        x = F.relu(F.max_pool2d(self.conv1(x), 2))\n",
    "        x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))\n",
    "        x = x.view(-1, 320)\n",
    "        x = F.relu(self.fc1(x))\n",
    "        x = F.dropout(x, training=self.training)\n",
    "        x = self.fc2(x)\n",
    "        return F.log_softmax(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "network = Net()\n",
    "optimizer = optim.SGD(network.parameters(), lr=learning_rate,\n",
    "                      momentum=momentum)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_losses = []\n",
    "train_counter = []\n",
    "test_losses = []\n",
    "test_counter = [i*len(train_loader.dataset) for i in range(n_epochs + 1)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-11-3149a0a29766>:16: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n",
      "  return F.log_softmax(x)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train Epoch: 6 [0/60000 (0%)]\tLoss: 0.223149\n",
      "Train Epoch: 6 [6400/60000 (11%)]\tLoss: 0.273245\n",
      "Train Epoch: 6 [12800/60000 (21%)]\tLoss: 0.241604\n",
      "Train Epoch: 6 [19200/60000 (32%)]\tLoss: 0.226408\n",
      "Train Epoch: 6 [25600/60000 (43%)]\tLoss: 0.323682\n",
      "Train Epoch: 6 [32000/60000 (53%)]\tLoss: 0.411012\n",
      "Train Epoch: 6 [38400/60000 (64%)]\tLoss: 0.388461\n",
      "Train Epoch: 6 [44800/60000 (75%)]\tLoss: 0.367156\n",
      "Train Epoch: 6 [51200/60000 (85%)]\tLoss: 0.396040\n",
      "Train Epoch: 6 [57600/60000 (96%)]\tLoss: 0.261678\n"
     ]
    }
   ],
   "source": [
    "def train(epoch):\n",
    "  network.train()\n",
    "  for batch_idx, (data, target) in enumerate(train_loader):\n",
    "    optimizer.zero_grad()\n",
    "    output = network(data)\n",
    "    loss = F.nll_loss(output, target)\n",
    "    loss.backward()\n",
    "    optimizer.step()\n",
    "    if batch_idx % log_interval == 0:\n",
    "      print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n",
    "        epoch, batch_idx * len(data), len(train_loader.dataset),\n",
    "        100. * batch_idx / len(train_loader), loss.item()))\n",
    "      train_losses.append(loss.item())\n",
    "      train_counter.append(\n",
    "        (batch_idx*64) + ((epoch-1)*len(train_loader.dataset)))\n",
    "          \n",
    "train(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-11-3149a0a29766>:16: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n",
      "  return F.log_softmax(x)\n",
      "D:\\ProgramFiles\\anaconda3\\lib\\site-packages\\torch\\nn\\_reduction.py:44: UserWarning: size_average and reduce args will be deprecated, please use reduction='sum' instead.\n",
      "  warnings.warn(warning.format(ret))\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Test set: Avg. loss: 0.0975, Accuracy: 9693/10000 (97%)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "def test():\n",
    "  network.eval()\n",
    "  test_loss = 0\n",
    "  correct = 0\n",
    "  with torch.no_grad():\n",
    "    for data, target in test_loader:\n",
    "      output = network(data)\n",
    "      test_loss += F.nll_loss(output, target, size_average=False).item()\n",
    "      pred = output.data.max(1, keepdim=True)[1]\n",
    "      correct += pred.eq(target.data.view_as(pred)).sum()\n",
    "  test_loss /= len(test_loader.dataset)\n",
    "  test_losses.append(test_loss)\n",
    "  print('\\nTest set: Avg. loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
    "    test_loss, correct, len(test_loader.dataset),\n",
    "    100. * correct / len(test_loader.dataset)))\n",
    "    \n",
    "test()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(28, 28)"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "img = cv2.imread('D:/data/7.jpg') #不要有中文，不要有空格\n",
    "img = cv2.resize(img, (28, 28), interpolation=cv2.INTER_NEAREST)\n",
    "img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转换方式,OpenCV在读取图像时会默认图像通道的顺序是BGR\n",
    "img.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "#展示图片\n",
    "plt.figure() #画布，dpi是分辨率\n",
    "plt.imshow(img)\n",
    "plt.axis('off'); #不显示坐标轴"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 1, 28, 28])"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "transform = torchvision.transforms.Compose([\n",
    "        torchvision.transforms.ToTensor(),\n",
    "        torchvision.transforms.Normalize(\n",
    "            (0.1307,), (0.3081,))\n",
    "        ])\n",
    "data = transform(img)\n",
    "data = data.view(1, 1, 28, 28)\n",
    "data.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "<ipython-input-11-3149a0a29766>:16: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.\n",
      "  return F.log_softmax(x)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "tensor([[7]])"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "output = network.forward(data)\n",
    "pred = output.data.max(1, keepdim=True)[1]\n",
    "pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
